/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.model.disc.fem;

import java.util.ArrayList;
import java.util.ListIterator;

import br.ufmg.dees.insane.crossSection.CrossSection;
import br.ufmg.dees.insane.materialMedia.material.LinearElasticIsotropic;
import br.ufmg.dees.insane.materialMedia.material.MSpring;
import br.ufmg.dees.insane.materialMedia.material.Material;
import br.ufmg.dees.insane.model.disc.analysismodel.AnalysisModel;
import br.ufmg.dees.insane.model.disc.element.Element;
import br.ufmg.dees.insane.model.disc.integrationorder.IntegrationOrder;
import br.ufmg.dees.insane.model.disc.node.Node;
import br.ufmg.dees.insane.model.disc.shape.Shape;

/**
*A class representing a FEM model.
*
*@author Fonseca, Flavio & Pitangueira, Roque
*@version 1.0
*@since September 2003
*@see Node
*@see Element
*@see Material
*@see AnalysisModel
*@see Shape
*/

public class FemModel implements java.io.Serializable {
	
	/**
	 * Comment for <code>serialVersionUID</code>
	 */
	private static final long serialVersionUID = 1L;

	/** This FemModel's Nodes list. */
	protected ArrayList<Node> nodes = new ArrayList<Node>();
	
	/** This FemModel's Elements list. */
	protected ArrayList<Element> elements = new ArrayList<Element>();
	
	/** This FemModel's Materials list. */
	protected ArrayList<Material> materials = new ArrayList<Material>();
	
	/**This FemModel's cross sections list.*/
	protected ArrayList<CrossSection> sections = new ArrayList<CrossSection>();
	
	/** This FemModel's AnalysisModel list. */
	protected ArrayList<AnalysisModel> analysisModels = new ArrayList<AnalysisModel>();
	
	/** This FemModel's Shapes list. */
	protected ArrayList<Shape> shapes = new ArrayList<Shape>();
	
	/** This FemModel's IntegrationOrder list. */
	protected ArrayList<IntegrationOrder> integrationOrders = new ArrayList<IntegrationOrder>();
	
	/** This FemModel's equations. */
	protected int[] equations;
	
	/** This FemModel's number of equations.<br>
	*It is the same of the number of degrees of freedom of this FemModel.
	*/
	protected int numEquations;
	
	/** This FemModel's global AnalysisModel. */
	protected AnalysisModel globalAnalysisModel;
	
	/** This FemModel's number of restraints.*/
	protected int numRestraints;
	
	/** Indicates if this FemModel is hypostatic or not.*/
	protected boolean isHypostatic = false;
	
//********************************************************************************
	
	/** Returns the number of Elements of this FemModel.
	*@return The number of Elements of this FemModel.
	*/
	public int getNumberOfElements(){
		return (elements.size());
	};
	
	/** Returns this FemModel's Elements list.
	*@return This FemModel's Elements list.
	*/
	public ArrayList getElementsList(){
		return (elements);
	};
	
	/** Returns the Element with the specified label.
	*@param a The label of the desired Element.
	*@return The Element with the specified label.
	*/
	public Element getElement(String a) {
		Element elm;
		ListIterator elms = elements.listIterator();
		while (elms.hasNext()) {
			elm = (Element) elms.next();
			if (elm.getLabel().equals(a)) {
				return (elm);
			};
		};
		return (null);
	};
	
	/** Adds the specified Element to the Element list.
	*@param a The Element to be added to the Element list.
	*/
	public void add(Element a) {
		elements.add(a);
	};
	
	/** Removes the specified Element.
	*@param a The Element to be removed.
	*/
	public void remove(Element a) {
		Element elm;
		ListIterator elms = elements.listIterator();
		while (elms.hasNext()) {
			elm = (Element) elms.next();
			if (elm.getLabel().equals(a.getLabel())) {
				elements.remove(elm);
			};
		};
	};
	
	/** Returns the number of Elements of this FemModel with MSpring Material.
	*@return The number of Elements of this FemModel with MSpring Material.
	*/
	public int getNumberOfRigidElements(){
		int num = 0;
		ListIterator elms = elements.listIterator();
		while (elms.hasNext()) {
			Element elm = (Element)elms.next();
			if (elm.getMaterial() instanceof LinearElasticIsotropic)
				num++;
		}
		return (num);
	}
	
	/** Returns the number of Elements of this FemModel with Isotropic Material.
	*@return The number of Elements of this FemModel with Isotropic Material.
	*/
	public int getNumberOfElasticElements(){
		int num = 0;
		ListIterator elms = elements.listIterator();
		while (elms.hasNext()) {
			Element elm = (Element)elms.next();
			if (elm.getMaterial() instanceof MSpring)
				num++;
		}
		return (num);
	}
	
	/** Returns the number of Elements of this FemModel without MSpring Material.
	*@return The number of Elements of this FemModel without MSpring Material.
	*/
	public int getNumberOfNonElasticElements(){
		int num = 0;
		ListIterator elms = elements.listIterator();
		while (elms.hasNext()) {
			Element elm = (Element)elms.next();
			if (!(elm.getMaterial() instanceof MSpring))
				num++;
		}
		return (num);
	}
	
//********************************************************************************
	
	/** Returns the number of Nodes of this FemModel.
	*@return The number of Nodes of this FemModel.
	*/
	public int getNumberOfNodes(){
		return (nodes.size());
	};
	
	/** Returns this FemModel's Nodes list.
	*@return This FemModel's Nodes list.
	*/
	public ArrayList getNodesList(){
		return (nodes);
	};
	
	/** Returns the Node with the specified label.
	*@param a The label of the desired Node.
	*@return The Node with the specified label.
	*/
	public Node getNode(String a) {
		Node node;
		ListIterator nds = nodes.listIterator();
		while (nds.hasNext()) {
			node = (Node) nds.next();
			if (node.getLabel().equals(a)) {
				return (node);
			};
		};
		return (null);
	};
	
	/** Returns the Node with the specified coords.
	*@param x The coord X of the desired Node.
	*@param y The coord Y of the desired Node.
	*@return The Node with the specified coords.
	*/
	public Node getNode(double x, double y) {
		Node node;
		ListIterator nds = nodes.listIterator();
		while (nds.hasNext()) {
			node = (Node) nds.next();
			if (node.getCoord().x == x && node.getCoord().y == y && node.getCoord().z == 0) {
				return (node);
			};
		};
		return (null);
	};
	
	/** Returns the Node with the specified coords.
	*@param x The coord X of the desired Node.
	*@param y The coord Y of the desired Node.
	*@param z The coord Z of the desired Node.
	*@return The Node with the specified coords.
	*/
	public Node getNode(double x, double y, double z) {
		Node node;
		ListIterator nds = nodes.listIterator();
		while (nds.hasNext()) {
			node = (Node) nds.next();
			if (node.getCoord().x == x && node.getCoord().y == y && node.getCoord().z == 0) {
				return (node);
			};
		};
		return (null);
	};
	
	/** Adds the specified Node to the Nodes list.
	*@param a The Node to be added to the Nodes list.
	*/
	public void add(Node a) {
		nodes.add(a);
	};
	
	/** Removes the specified Node.
	*@param a The Node to be removed.
	*/
	public void remove(Node a) {
		Node node;
		ListIterator nds = nodes.listIterator();
		while (nds.hasNext()) {
			node = (Node) nds.next();
			if (node.getLabel().equals(a.getLabel())) {
				nodes.remove(node);
			};
		};
	};
	
//********************************************************************************
	
	/** Returns the number of Materials of this FemModel.
	*@return The number of Materials of this FemModel.
	*/
	public int getNumberOfMaterials(){
		return (materials.size());
	};
	
	/** Returns this FemModel's Materials list.
	*@return This FemModel's Materials list.
	*/
	public ArrayList getMaterialsList(){
		return (materials);
	};
	
	/** Returns the Material with the specified label.
	*@param a The label of the desired Material.
	*@return The Material with the specified label.
	*/
	public Material getMaterial(String a) {
		Material mat;
		ListIterator mats = materials.listIterator();
		while (mats.hasNext()) {
			mat = (Material) mats.next();
			if (mat.getLabel().equals(a)) {
				return (mat);
			};
		};
		return (null);
	};
	
	/** Adds the specified Material to the Materials list.
	*@param a The Material to be added to the Materials list.
	*/
	public void add(Material a)
	{
		Material mat;
		ListIterator mats = materials.listIterator();
		
		if(!mats.hasNext())
			materials.add(a);
		else
		{
			while (mats.hasNext())
			{
				mat = (Material) mats.next();
				
				if (mat.getLabel().equals(a.getLabel()))return;
			}
			materials.add(a);
		}
	};
	
	/** Removes the specified Material.
	*@param a The Material to be removed.
	*/
	public void remove(Material a) {
		Material mat;
		ListIterator mats = materials.listIterator();
		while (mats.hasNext()) {
			mat = (Material) mats.next();
			if (mat.getLabel().equals(a.getLabel())) {
				materials.remove(mat);
			};
		};
	};
	
	/** Returns the number of Isotropic Materials of this FemModel.
	*@return The number of Isotropic Materials of this FemModel.
	*/
	public int getNumberOfIsotropicMaterials(){
		int num = 0;
		Material mat;
		ListIterator mats = materials.listIterator();
		while (mats.hasNext()) {
			mat = (Material) mats.next();
			if (mat instanceof LinearElasticIsotropic) {
				num++;
			}
		}
		return (num);
	}
	
//********************************************************************************
	
	/** Returns the number of AnalysisModels of this FemModel.
	*@return The number of AnalysisModels of this FemModel.
	*/
	public int getNumberOfAnalysisModels(){
		return (analysisModels.size());
	};
	
	/** Returns this FemModel's AnalysisModels list.
	*@return This FemModel's AnalysisModels list.
	*/
	public ArrayList getAnalysisModelsList(){
		return (analysisModels);
	};
	
	/** Returns the AnalysisModel with the specified label.
	*@param a The label of the desired AnalysisModel.
	*@return The AnalysisModel with the specified label.
	*/
	public AnalysisModel getAnalysisModel(String a) {
		AnalysisModel am;
		ListIterator ams = analysisModels.listIterator();
		while (ams.hasNext()) {
			am = (AnalysisModel) ams.next();
			if (am.getType().equals(a)) {
				return (am);
			};
		};
		return (null);
	};
	
	/** Adds the specified AnalysisModel to the AnalysisModels list.
	*@param a The AnalysisModel to be added to the AnalysisModels list.
	*/
	public void add(AnalysisModel a)
	{
		AnalysisModel anl;
		ListIterator anls = analysisModels.listIterator();
		
		if(!anls.hasNext())
			analysisModels.add(a);
		else
		{
			while (anls.hasNext())
			{
				anl = (AnalysisModel) anls.next();
				
				if (anl.getType().equals(a.getType()))return;
			}
			analysisModels.add(a);
		}
	};
	
	/** Removes the specified AnalysisModel.
	*@param a The AnalysisModel to be removed.
	*/
	public void remove(AnalysisModel a) {
		AnalysisModel anl;
		ListIterator anls = analysisModels.listIterator();
		while (anls.hasNext()) {
			anl = (AnalysisModel) anls.next();
			if (anl.getType().equals(a.getType())) {
				analysisModels.remove(anl);
			};
		};
	};
	
//********************************************************************************
	
	/** Returns the number of Shapes of this FemModel.
	*@return The number of Shapes of this FemModel.
	*/
	public int getNumberOfShapes(){
		return (shapes.size());
	};
	
	/** Returns the Shape with the specified label.
	*@param a The label of the desired Shape.
	*@return The Shape with the specified label.
	*/
	public Shape getShape(String a)
	{
		Shape shape;
		ListIterator shps = shapes.listIterator();
		while (shps.hasNext())
		{
			shape = (Shape) shps.next();
			if (shape.getType().equals(a))
			{
				return (shape);
			}
		}
		return (null);
	}
	
	/** Returns this FemModel's Shapes list.
	*@return This FemModel's Shapes list.
	*/
	public ArrayList getShapesList(){
		return (shapes);
	};
	
	/** Adds the specified Shape to the Shapes list.
	*@param a The Shape to be added to the Shapes list.
	*/
	public void add(Shape a) {
		Shape shp;
		ListIterator shps = shapes.listIterator();
		
		if(!shps.hasNext())
			shapes.add(a);
		else
		{
			while (shps.hasNext())
			{
				shp = (Shape) shps.next();
				
				if (shp.getType().equals(a.getType()))return;
			}
			shapes.add(a);
		}
	};

//********************************************************************************
	
	/** Returns the number of equations of this FemModel.
	*@return The number of equations of this FemModel.
	*/
	public int getNumberOfEquations(){
		return (numEquations);
	};
	
	/** Sets the number of equations of this FemModel.
	*@param a The number of equations of this FemModel.
	*/
	public void setNumberOfEquations(int a){
		numEquations = a;
	};
	
//********************************************************************************
	
	/** Returns the number of restraints of this FemModel.
	*@return The number of restraints of this FemModel.
	*/
	public int getNumberOfRestraints(){
		return (numRestraints);
	};
	
	/** Sets the number of restraints of this FemModel.
	*@param a The number of restraints of this FemModel.
	*/
	public void setNumberOfRestraints(int a){
		numRestraints = a;
	};
	
//********************************************************************************
	
	/** Returns this FemModel's IntegrationOrder list.
	*@return This FemModel's IntegrationOrder list.
	*/
	public ArrayList getIntegrationOrdersList()
	{
		return (integrationOrders);
	}
	
	/** Adds the specified IntegrationOrder to the IntegrationOrders list.
	*@param a The IntegrationOrder to be added to the IntegrationOrders list.
	*/
	public void add(IntegrationOrder a)
	{
		IntegrationOrder integrationOrder;
		ListIterator intOrds = integrationOrders.listIterator();
		
		if(!intOrds.hasNext())
			integrationOrders.add(a);
		else
		{
			while (intOrds.hasNext())
			{
				integrationOrder = (IntegrationOrder) intOrds.next();
				
				if (integrationOrder.getLabel().equals(a.getLabel()))return;
			}
			integrationOrders.add(a);
		}
	}
	
	/** Returns the IntegrationOrder with the specified label.
	*@param a The label of the desired IntegrationOrder.
	*@return The IntegrationOrder with the specified label.
	*/
	public IntegrationOrder getIntegrationOrder(String a)
	{
		IntegrationOrder integrationOrder;
		ListIterator intOrds = integrationOrders.listIterator();
		
		while (intOrds.hasNext())
		{
			integrationOrder = (IntegrationOrder) intOrds.next();
			if (integrationOrder.getLabel().equals(a))
			{
				return (integrationOrder);
			}
		}
		return (null);
	}

//********************************************************************************
	
	/** Returns the global AnalysisModel of this FemModel.
	*@return The global AnalysisModel of this FemModel.
	*/
	public AnalysisModel getGlobalAnalysisModel(){
		return (globalAnalysisModel);
	};
	
	/** Sets the global AnalysisModel of this FemModel.
	*@param a The global AnalysisModel of this FemMode.
	*/
	public void setGlobalAnalysisModel(AnalysisModel a){
		globalAnalysisModel = a;
	};
	
//********************************************************************************
		
	/** Returns the number of CrossSections of this FemModel.
	*@return The number of CrossSections of this FemModel.
	*/
	public int getNumberOfSections()
	{
		return (sections.size());
	}
	
	/** Returns this FemModel's sections list.
	*@return This FemModel's sections list.
	*/
	public ArrayList getSectionsList()
	{
		return (sections);
	}
	
	/** Returns the CrossSection with the specified label.
	*@param a The label of the desired CrossSection.
	*@return The CrossSection with the specified label.
	*/
	public CrossSection getCrossSection(String a) 
	{
		CrossSection cs;
		ListIterator css = sections.listIterator();
		while (css.hasNext())
		{
			cs = (CrossSection) css.next();
			if (cs.getLabel().equals(a))
			{
				return (cs);
			}
		}
		return (null);
	}
	
	/** Adds the specified CrossSection to the cross sections list.
	*@param a The CrossSection to be added to the cross sections list.
	*/
	public void add(CrossSection a)
	{
		CrossSection cs;
		ListIterator css = sections.listIterator();
		
		if(!css.hasNext())
			sections.add(a);
		else
		{
			while (css.hasNext())
			{
				cs = (CrossSection) css.next();
				
				if (cs.getLabel().equals(a.getLabel()))return;
			}
			sections.add(a);
		}
	}
	
	/** Removes the specified CrossSection.
	*@param a The CrossSection to be removed.
	*/
	public void remove(CrossSection a)
	{
		CrossSection cs;
		ListIterator css = sections.listIterator();
		while (css.hasNext())
		{
			cs = (CrossSection) css.next();
			if (cs.getLabel().equals(a.getLabel()))
			{
				sections.remove(cs);
			}
		}
	}
	
//********************************************************************************
	
	/** Clears all attributes of this FemModel, including lists.*/
	public void clearAll() {
		nodes.clear();
		elements.clear();
		materials.clear();
		analysisModels.clear();
		shapes.clear();
		sections.clear();
		integrationOrders.clear();
		numEquations = 0;
		numRestraints = 0;
	}
	
//********************************************************************************
	
	/** Sets the value of isHypostatic variable.
	* @param a The value to be set.
	*/
	public void setHypostatic(boolean a) {
		isHypostatic = a;
	}
	
	/** Returns the value of isHypostatic variable.
	* @return The value isHypostatic variable.
	*/
	public boolean isHypostatic() {
		return isHypostatic;
	}
	
//********************************************************************************
	
	/** Sets to zero all the results calculated. */
	public void cleanResults() {
		
		//FemModel results
		numEquations = 0;
		numRestraints = 0;
		isHypostatic = false;
		
		//Elements results
		ListIterator i = elements.listIterator();
		while (i.hasNext()) {
			Element elm = (Element)i.next();
			elm.cleanResults();
		}
		
		//Nodes results
		i = nodes.listIterator();
		while (i.hasNext()) {
			Node no = (Node)i.next();
			no.cleanResults();
		}
		
	}
	
//********************************************************************************
    public void updateState(){

        ListIterator i = elements.listIterator();
        while (i.hasNext()) {
            Element elm = (Element)i.next();
            elm.updateState();
        } 
     }
//********************************************************************************
}
